#ifndef __PALMVEIN_PROTOCOL_H__
#define __PALMVEIN_PROTOCOL_H__

#include "palmvein_com.h"

///////////////// TX-CMD //////////////////////////////////////////////////////////

/* 位操作宏 */
#define BIT(n) (0x1 << n)
#define BIT_SET(x, n) (x |= BIT(n))
#define BIT_TEST(x, n) ((x & BIT(n)) != 0)
#define BIT_CLEAR(x, n) (x &= ~BIT(n))
#define SWAP16(n) ((((uint16_t)(n) >> 8) & 0x00FF) | (((uint16_t)(n) << 8) & 0xFF00))
#define SWAP32(n) (((((uint32_t)n) >> 24) & 0xFF) | (((uint32_t)(n) >> 8) & 0xFF00) | (((uint32_t)(n) << 8) & 0xFF0000) | (((uint32_t)(n) << 24) & 0xFF000000))

#define __LITTLE_ENDIAN 1

#ifdef __LITTLE_ENDIAN
#define A2U16(a) ((uint16_t)(a[0] | (a[1] << 8)) & 0xFFFF)
#define A2U32(a) (uint32_t)(a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24))
#else
#define A2U16(a) ((uint16_t)(a[1] | (a[0] << 8)) & 0xFFFF)
#define A2U32(a) (uint32_t)(a[3] | (a[2] << 8) | (a[1] << 16) | (a[0] << 24))
#endif

#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define BCD_TIME_FMT "20%02X/%02X/%02X %02X:%02X:%02X"
#define PRINT_MAC(a) a[0], a[1], a[2], a[3], a[4], a[5]

#define PRINT_TIME(a) PRINT_MAC(a)

#define SENSE_TIME_CMD_DATA_LEN 64							//锁发送人掌静脉命令的数据长度
#define SENSE_TIME_CMD_OTA_DATA_LEN SENSE_TIME_CMD_DATA_LEN //(SENSE_TIME_CMD_DATA_LEN+FIRMWARE_PACKAGE_LEN)
#define USER_NAME_SIZE 32									//录入用户名
#define ACK_RES_TIMEOUT 0XFF //操作超时

#define MID_REPLY 0x00 		//模块对主控发送出的命令的应答
#define MID_NOTE 0x01  		//模块主动发给主控的信息

/* 锁发出的命令 */
#define MID_RESET 0x10				 // stop and clear all in-processing messages. enter standby mode
#define MID_GETSTATUS 0x11			 // to ping the module and get the status
#define MID_VERIFY 0x12				 // to verify the person in front of the camera
#define MID_ENROLL 0x13				 // to enroll and register the persion in front of the cameraconst
#define MID_ENROLL_SINGLE 0x1D		 // to enroll and register the persion in front of the camera, with one frame image
#define MID_SNAPIMAGE 0x16			 // to snap a picture and save it
#define MID_GETSAVEDIMAGE 0x17		 // to get size of saved image
#define MID_UPLOADIMAGE 0x18		 // upload images
#define MID_DELUSER 0x20			 // Delete the specified user with user id
#define MID_DELALL 0x21				 // Delete all registerred users
#define MID_GETUSERINFO 0x22		 // Get user info
#define MID_PALMVEINRESET 0x23			 // Reset palmvein status
#define MID_GET_ALL_USERID 0x24		 // get all users ID
#define MID_GET_VERSION 0x30		 // get version information
#define MID_WRITE_SN 0x31			 // write sn to board
#define MID_START_OTA 0x40			 // ask the module to enter OTA mode
#define MID_STOP_OTA 0x41			 // ask the module to exit OTA mode
#define MID_GET_OTA_STATUS 0x42		 // query the current ota status
#define MID_OTA_HEADER 0x43			 // the ota header data
#define MID_OTA_PACKET 0x44			 // the data packet, carries real firmware data
#define MID_INIT_ENCRYPTION 0x50	 // initialize encrypted communication
#define MID_CONFIG_BAUDRATE 0x51	 // config uart baudrate
#define MID_SET_RELEASE_ENC_KEY 0x52 // set release encrypted key(Warning!!!:Once set, the KEY will not be able to modify)
#define MID_SET_DEBUG_ENC_KEY 0x53	 // set debug encrypted key
#define MID_GET_LOGFILE 0x60		 // get log file
#define MID_UPLOAD_LOGFILE 0x61		 // upload log file
#define MID_ENABLE_ATTRIBUTE 0x80	 //微笑模式设置（验证时微笑才能验证成功）
#define MID_FACTORY_TEST 0xC0		 // factory test
#define MID_DDR_TEST 0xC1			 // DDR test
#define MID_SET_THRESHOLD_LEVEL 0xD4 // Set threshold level
#define MID_POWERDOWN 0xED			 // be prepared to power off
#define MID_DEBUG_MODE 0xF0
#define MID_GET_DEBUG_INFO 0xF1	   // get size of debug information
#define MID_UPLOAD_DEBUG_INFO 0xF2 // upload debug information
#define MID_FACTORY_RESET			0xF8	//恢复出厂设置
#define MID_DEMOMODE 0xFE		   // enter demo mode, verify flow will skip feature comparation step.
#define MID_MAX 0xFF			   // reserved

/* 锁命令发出后，模组应答的结果 */
#define MR_SUCCESS 0x00				  //成功
#define MR_REJECTED 0X01			  //模块拒接该命令
#define MR_ABORTED 0x02				  //录入/解锁算法已终止
#define MR_FAILED4_CAMERA 0X04		  //相机打开失败
#define MR_FAILED4_UNKNOWNREASON 0x05 //未知错误
#define MR_FAILED4_INVALIDPARAM 0x06  //无效的参数
#define MR_FAILED4_NOMEMORY 0x07	  //内存不足
#define MR_FAILED4_UNKNOWNUSER 0x08	  //没有已录入的用户
#define MR_FAILED4_MAXUSER 0x09		  //录入超过最大用户数量
#define MR_FAILED4_PALMVEINENROLLED 0x10  //掌静脉已录入
#define MR_FAILED4_LIVENESSCHECK 0x12 //活体检测失败
#define MR_FAILED4_TIMEOUT 0x13		  //录入或解锁超时
#define MR_FAILED4_AUTHORIZATION 0x14 //加密芯片授权失败
#define MR_FAILED4_WITHOUTSMILE 0x16  //验证未微笑
#define MR_FAILED4_READ_FILE 0x19	  //读文件失败
#define MR_FAILED4_WRITE_FILE 0x20	  //写文件失败
#define MR_FAILED4_NO_ENCRYPT 0x21	  //通信协议未加密

/*M->H模组主动向主控发送的消息 note*/
#define NID_READY 0x00		  //模块已准备好
#define NID_PALMVEIN_STATE 0x04	  //算法执行成功，并且返回掌静脉信息 s_note_data_palmvein
#define NID_UNKNOWNERROR 0x02 //未知错误
#define NID_OTA_DONE 0x03	  //OTA升级完毕


/*掌静脉信息s_note_data_palmvein 掌静脉状态*/
#define PALMVEIN_STATE_NORMAL 0x00			   //掌静脉正常
#define PALMVEIN_STATE_NOPALMVEIN 0x01		   //未检测到掌静脉
#define PALMVEIN_STATE_NOTMID 0x02			   //手掌未居中
#define PALMVEIN_STATE_TOOUP 0x03			   //手掌放置太高
#define PALMVEIN_STATE_TOODOWN 0x04			   //手掌放置太低

//TODO
#define PALMVEIN_STATE_TOOLRIGHT 0x05		   //掌静脉太考经图片右边沿，未能录入
#define PALMVEIN_STATE_FAR 0x06				   //掌静脉距离太远，未能录入
#define PALMVEIN_STATE_CLOSE 0x07			   //掌静脉距离太近，未能录入
#define PALMVEIN_STATE_EYEBROW_OCCLUSION 0x08  //眉毛遮挡
#define PALMVEIN_STATE_EYE_OCCLUSION 0x09	   //眼睛遮挡
#define PALMVEIN_STATE_PALMVEIN_OCCLUSION 0x0A	   //脸部遮挡
#define PALMVEIN_STATE_DIRECTION_ERROR 0x0B	   //录入掌静脉方向错误
#define PALMVEIN_STATE_EYE_CLOSE_OPEN_EYE 0x0C //在闭眼模式检测到睁眼状态
#define PALMVEIN_STATE_EYE_CLOSE_STATUS 0x0D   //闭眼状态
#define PALMVEIN_STATE_EYE_ClOSE_UNKNOW 0x0E   //闭眼模式检测中无法判定睁闭眼状态

/*验证指令结果宏定义*/

/*unlockStatus*/
#define ST_PALMVEIN_MODULE_STATUS_UNLOCK_OK 200				 // 正常解锁
#define ST_PALMVEIN_MODULE_STATUS_UNLOCK_WITH_EYES_CLOSE 204 // 闭眼解锁

/* msg palmvein direction */
typedef uint8_t s_palmvein_dir;

#define PALMVEIN_DIRECTION_UP 0x10		 // palmvein up
#define PALMVEIN_DIRECTION_DOWN 0x08	 // palmvein down
#define PALMVEIN_DIRECTION_LEFT 0x04	 // palmvein left
#define PALMVEIN_DIRECTION_RIGHT 0x02	 // palmvein right
#define PALMVEIN_DIRECTION_MIDDLE 0x01	 // palmvein middle
#define PALMVEIN_DIRECTION_UNDEFINE 0x00 // palmvein undefine
#define PALMVEIN_DIRECTION_ALL 0x1F		 //所有掌静脉方向

/* msg palmvein direction end */

/*加密模式*/
#define ST_ENCMODE_DEFAULT 0x00 //默认模式
#define ST_ENCMODE_AES 0x01		//AES加密
#define ST_ENCMODE_SMPL 0x02	//取反异或加密

/* 消息回调函数类型 */
typedef void (*PalmVeinMessageCallback_fun_t)(uint8_t result, uint8_t *data, uint8_t len);

/**********************************门锁发送指令结构体**************************************/
#pragma pack(1)
/* 锁发送命令给掌静脉模组消息结构 */
typedef struct
{
	uint8_t msgID;
	PalmVeinMessageCallback_fun_t cb;
	uint16_t data_len;
	uint32_t timeout;
	uint8_t dataBuf[SENSE_TIME_CMD_OTA_DATA_LEN];
} Palmvein_P_TxCmdMsg_stu_t;

/* 锁发送掌静脉验证消息结构 */
typedef struct
{
	uint8_t pd_rightaway; // 保留参数  （是否在解锁后立刻关机）
	uint8_t timeout;	  // timeout, unit second, default 10s 允许值0~255
} s_msg_verify_data;

/*锁发送设置微笑模式结构*/
typedef struct
{
	uint8_t flag;
} s_msg_attribute_data;

/* 锁发送掌静脉录入消息结构 */
typedef struct
{
	uint8_t admin; // the user will be set to admin 是否设置为管理员(yes:1 no:0 )
	uint8_t user_name[USER_NAME_SIZE];
	uint8_t reserved; // 预留
	uint8_t timeout; // timeout, unit second default 10s
} s_msg_enroll_data;

/* 锁发送删除单个掌静脉消息结构 */
typedef struct
{
	uint8_t user_id_heb; // high eight bits of user_id to be deleted
	uint8_t user_id_leb; // low eight bits pf user_id to be deleted
} s_msg_deluser_data;

/*启动OTA升级*/
typedef struct
{
	uint8_t v_primary;	 // primary version number
	uint8_t v_secondary; //secondary version number
	uint8_t v_revision;	 //revision number
						 //uint8_t ota_type;     //ota partition: 0:OS, 1:palmveinlib
} s_msg_startota_data;

/* 锁发送设置波特率消息结构 */
typedef struct
{
	uint8_t baudrate_index; //1: is 115200 (115200*1); 2 is 230400 (115200*2); 3 is 460800 (115200*4); 4 is 1500000
} s_msg_config_baudrate;

/*锁发送固件包头信息*/
typedef struct
{
	uint8_t fsize_b[4];	 // OTA FW file size int -> [b1, b2, b3, b4] OTA升级包的大小
	uint8_t num_pkt[4];	 // number packet to be divided for trans ferring, int -> [b1, b2, b3, b4] 分包的个数
	uint8_t pkt_size[2]; // raw data size of single packet分包的大小，最大不超过4KBytes
	uint8_t md5_sum[32]; // md5 check sum 升级包的md5
} s_msg_otaheader_data;

/*锁发送固件包给掌静脉模组*/
typedef struct
{
	uint16_t pid;	// the packet id
	uint16_t psize; // the size of this package
	uint8_t data[]; // data 0 start
} s_msg_otapacket_data;

/* 锁发送设置debug模式消息结构 */
typedef struct
{
	uint8_t mode; //  1：debug mode    0：work mode
} s_msg_set_debugmode;

/* 锁发送加密key的逻辑*/
typedef struct
{
	uint8_t enc_key_number[16]; //
} s_msg_enc_key_number_data;

/*发送密钥设置*/
typedef struct
{
	uint8_t seed[4];	// 随机序列
	uint8_t mode;		// 指定 mode 0
	uint8_t crttime[4]; // 同步主控时间给模组 (时间戳)
} s_msg_init_encryption_data;


typedef struct 
{
	uint8_t user_counts;
	uint8_t users_id[100];
}s_msg_reply_all_userid_data;


/*设置算法安全等级*/
typedef struct
{
	uint8_t verify_threshold_level;		//level 0~4, safety from low to high,default 2
	uint8_t liveness_threshold_level;	// level 0~4, safety from low to high,default 2
} s_msg_algo_threshold_level;

/**********************************门锁发送指令结构体结束**************************************/

/**********************************掌静脉模组应答结构体**************************************/

/*掌静脉验证应答*/
typedef struct
{
	uint8_t user_id_heb;			   //已验证用户的ID高字节
	uint8_t user_id_leb;			   //已验证用户的ID低字节
	uint8_t user_name[USER_NAME_SIZE]; //用户名字
	uint8_t admin;					   //是否为管理员
	uint8_t unlockStatus;			   //解锁过程中睁闭眼状态
} s_msg_reply_verify_data;

/*掌静脉录入应答*/
typedef struct
{
	uint8_t user_id_heb;
	uint8_t user_id_leb;
	uint8_t capture_num;	//抓拍次数
} s_msg_reply_enroll_data;

/*掌静脉查询OTA状态应答*/
typedef struct
{
	uint8_t ota_status;	 //4：表示处于 OTA状态
	uint16_t next_pid_e; //传输固件包的起始序号
} s_msg_reply_getOtaStatus_data;

/*获取掌静脉软件版本应答*/
typedef struct
{
	uint8_t version_info[VERSION_INFO_BUFFER_SIZE];
} s_msg_reply_version_data;

typedef struct
{
	uint8_t device_id[PALMVEIN_SN_LEN];
} s_msg_reply_init_encryption_data;
/**********************************掌静脉模组应答结构体结束**************************************/

/**********************************掌静脉模组note结构体**************************************/
typedef struct
{
	int16_t status; // corresponding to PALMVEIN_STATE_*

	// position
	int32_t reserve; // 预留
} s_note_data_palmvein;

typedef struct
{
	uint8_t result; //OTA升级结果
} s_note_ota_done;
/**********************************掌静脉模组note结构体结束**************************************/
/*掌静脉验证和录入时返回的掌静脉状态信息*/
typedef struct
{
	int16_t status; //掌静脉状态
	// position
	int16_t left; // in pixel
	int16_t top;
	int16_t right;
	int16_t bottom;

	// pose
	int16_t yaw;   // right or left turned in horizontal orientation
	int16_t pitch; // up and down in vertical orientation
	int16_t roll;  // slope
} Palmvein_NotePalmveinStatus_stu_t;


#pragma pack()

extern void Palmvein_Event_Deal(Palmvein_DealParam_stu_t *param);

void Palmvein_P_Nid_Ready(void);
void Palmvein_P_Nid_Palmvein_Status(uint8_t *pNoteDataBuf);
void Palmvein_P_Nid_Ota_Done(uint8_t *pNoteDataBuf);
void Palmvein_P_Send_StartVerity_CMD(uint8_t time);
void Palmvein_P_Send_SetAttribute_CMD(uint8_t flag);
void Palmvein_P_Send_PowerDowm_CMD(void);
void Palmvein_P_Send_StartEnrollSingle_CMD(uint8_t num,uint8_t type);
void Palmvein_P_Send_StartEnroll_CMD(uint8_t num,uint8_t type);
void Palmvein_P_Send_Start_DelUser_CMD(uint16_t user_id);
void Palmvein_P_Send_Start_DelAll_CMD(void);
void Palmvein_P_Send_StartOta_CMD(void);
void Palmvein_P_Send_GetOtaStatus_CMD(void);
void Palmvein_P_Send_StopOta_CMD(void);
void Palmvein_P_Send_SetDemoMode_CMD(uint8_t mode);
void Palmvein_P_Send_DebugEncrytionKeyNum_Cmd(uint8_t *data, uint8_t datalen);
void Palmvein_P_Send_InitEncryption_CMD(uint8_t *seed, uint8_t seedlen, uint8_t *time, uint8_t timelen);
void Palmvein_P_Send_Get_Version_CMD(void);
void Palmvein_P_Send_ReleaseEncrytionKeyNum_Cmd(uint8_t *data, uint8_t datalen);
void Palmvein_P_Send_SetThresholdLevel_Cmd(uint8_t verify_threshold_level, uint8_t liveness_threshold_level);
void Palmvein_P_Send_Reset_CMD(void);
void Palmvein_P_Send_PalmveinReset_CMD(void);
void Palmvein_P_Send_GetAllUserid_CMD(void);
void Palmvein_P_Send_OtaFwInfo_CMD(uint8_t *data);
void Palmvein_P_Send_GetOtaStatus_CMD(void);
void Palmvein_P_Send_OtaCfgBaud_CMD(uint8_t data);

void Palmvein_P_OtaPack_Callback(uint8_t result, uint8_t *data, uint8_t len);		//ota分包回调

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif /* __NETWORK_PROTOCOL_H__ */
